package chapter8.eg5;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
import org.junit.Test;

public class ChannelOptionExample {
  @Test
  public void testChannelOptionClient() throws InterruptedException {
    final AttributeKey<Integer> id = AttributeKey.newInstance("ID");
    Bootstrap bootstrap = new Bootstrap();
    bootstrap.group(new NioEventLoopGroup())
        .channel(NioSocketChannel.class)
        .handler(new SimpleChannelInboundHandler<ByteBuf>() {
          @Override
          public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            Integer idValue = ctx.channel().attr(id).get();
            System.out.println("read from channel attr id: " + idValue);
          }

          @Override
          protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
            System.out.println("Received data: " + msg.toString(CharsetUtil.UTF_8));
          }

          @Override
          public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.writeAndFlush(Unpooled.copiedBuffer("Send data to server".getBytes()));
          }
        });

    bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
        .attr(id, 123456)
        .connect(new InetSocketAddress("127.0.0.1", 8080))
        .syncUninterruptibly();
    TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
  }

  @Test
  public void testChannelOptionServer() throws InterruptedException {
    ServerBootstrap bootstrap = new ServerBootstrap();
    bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup())
        .channel(NioServerSocketChannel.class)
        .childHandler(new ChannelInitializer<SocketChannel>() {
          @Override
          protected void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new SimpleChannelInboundHandler<ByteBuf>() {
              @Override
              protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
                System.out.println("Received data: " + msg.toString(CharsetUtil.UTF_8));
              }

              @Override
              public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
                Attribute<Integer> id = ctx.channel().attr(AttributeKey.newInstance("ID"));
                System.out.println("Received Id from client: " + id.get());
                ctx.writeAndFlush(Unpooled.copiedBuffer("Send response from server".getBytes()));
              }
            });
          }
        });

    bootstrap.bind(new InetSocketAddress(8080)).syncUninterruptibly();
    TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
  }

}
